﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// This is used to work out vertical edges. 
    /// </summary>
    public class EdgeDetectVertical : BaseImageFilter
    {
        /// <summary>
        /// Default constructor
        /// </summary>
        public EdgeDetectVertical()
        {
        }

        /// <summary>
        /// used by clone to create a deep copy
        /// </summary>
        /// <param name="_edgeDetectVertical"></param>
        internal EdgeDetectVertical(EdgeDetectVertical _edgeDetectVertical)
        {
        }

        /// <summary>
        /// detect the vertical Edges.
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap bmTemp = (UnsafeBitmap)_bitmap.Clone();

            // GDI+ still lies to us - the return format is BGR, NOT RGB.
            BitmapData bmData = _bitmap.BitmapData; //_bitmap.LockBits(new Rectangle(0, 0, _bitmap.Width, _bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData bmData2 = bmTemp.BitmapData; // bmTemp.LockBits(new Rectangle(0, 0, _bitmap.Width, _bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            int stride = bmData.Stride;
            IntPtr Scan0 = bmData.Scan0;
            IntPtr Scan02 = bmData2.Scan0;

            int nByteCount = _bitmap.BytesPerPixelCount;

            unsafe
            {
                byte* p = (byte*)(void*)Scan0;
                byte* p2 = (byte*)(void*)Scan02;

                int nOffset = stride - _bitmap.Width * nByteCount; //stride - _bitmap.Width * 3;
                int nWidth = _bitmap.Width * nByteCount; //_bitmap.Width * 3;

                int nPixel = 0;

                int nStride2 = stride * 2; //int nStride2 = stride * 2;
                int nStride3 = stride * 3; //int nStride3 = stride * 3;

                p += nStride3;
                p2 += nStride3;

                int nHeight = _bitmap.Height;
                for (int y = 3; y < nHeight - 3; ++y)
                {
                    p += nByteCount; //p += 3;
                    p2 += nByteCount; //p2 += 3;

                    for (int x = nByteCount; x < nWidth - nByteCount; ++x) //for (int x = 3; x < nWidth - 3; ++x)
                    {
                        int nValue = 2; //nValue was 3 before changes occurred...
                       nPixel = ((p2 + nStride3 + nValue)[0] +
                            (p2 + nStride2 + nValue)[0] +
                            (p2 + stride + nValue)[0] +
                            (p2 + nValue)[0] +
                            (p2 - stride + nValue)[0] +
                            (p2 - nStride2 + nValue)[0] +
                            (p2 - nStride3 + nValue)[0] -
                            (p2 + nStride3 - nValue)[0] -
                            (p2 + nStride2 - nValue)[0] -
                            (p2 + stride - nValue)[0] -
                            (p2 - nValue)[0] -
                            (p2 - stride - nValue)[0] -
                            (p2 - nStride2 - nValue)[0] -
                            (p2 - nStride3 - nValue)[0]);

                        if (nPixel < 0) nPixel = 0;
                        if (nPixel > 255) nPixel = 255;

                        p[0] = (byte)nPixel;

                        ++p;
                        ++p2;
                    }
                    p += nByteCount + nOffset; //p += 3 + nOffset;
                    p2 += nByteCount + nOffset; //p2 += 3 + nOffset;
                }
            }

            bmTemp.Dispose();
            return _bitmap;
        }

        /// <summary>
        /// used to create a deep copy
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new EdgeDetectVertical(this);
        }
    }
}
